package de.tub.bazinga.audio;

import java.io.File;
import java.io.FilenameFilter;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.Set;

import processing.core.PApplet;
import ddf.minim.AudioPlayer;
import ddf.minim.Minim;

public class AudioManagerImpl implements IAudioManager {

	/**
	 * Singleton
	 */
	private static AudioManagerImpl instance;

	/**
	 * Constants
	 */
	private static final String SOUND_HIT = "./sounds/hit/peng.mp3";
	private static final String SOUND_COUNTDOWN = "./sounds/countdown.mp3";
	public static final String SOUND_YMCA = "./sounds/background/ymca.mp3";

	private static final String FOLDER_BACKGROUND_MUSIC = "./sounds/background";
	private static final String FORMAT_BACKGROUND_MUSIC = ".mp3";

	/**
	 * Sounds
	 */
	private AudioPlayer soundHit = null;
	private AudioPlayer soundCountdown = null;

	private List<AudioPlayer> backgroundSounds = null;

	/**
	 * Minim
	 */
	private final Minim minim;

	/**
	 * States
	 */
	private boolean playingBackgroundMusic = false;
	private AudioPlayer currentBackgroundSound = null;

	private AudioManagerImpl(PApplet p) {
		minim = new Minim(p);
		soundHit = minim.loadFile(SOUND_HIT);
		soundCountdown = minim.loadFile(SOUND_COUNTDOWN);

		backgroundSounds = new LinkedList<AudioPlayer>();
		Set<File> backgroundMusicFiles = loadBackgroundMusic();
		for (File file : backgroundMusicFiles) {
			AudioPlayer player = minim.loadFile(file.getAbsolutePath());
			backgroundSounds.add(player);
		}
		currentBackgroundSound = backgroundSounds.get(0);
	}

	private Set<File> loadBackgroundMusic() {
		// File musicFolder = new File(FOLDER_BACKGROUND_MUSIC);

		File musicFolder = new File(AudioManagerImpl.class.getClassLoader()
				.getResource(FOLDER_BACKGROUND_MUSIC).getPath());

		File[] musicFilePath = musicFolder.listFiles(new FilenameFilter() {

			@Override
			public boolean accept(File dir, String name) {
				if (name.endsWith(FORMAT_BACKGROUND_MUSIC)) {
					return true;
				} else {
					return false;
				}
			}
		});

		return new HashSet<File>(Arrays.asList(musicFilePath));

	}

	@Override
	public void playHitSound() {
		soundHit.rewind();
		soundHit.play();
	}

	@Override
	public void playGameFinishedSound() {
		// TODO
	}

	@Override
	public void playCountdownSound() {
		soundCountdown.rewind();
		soundCountdown.play();
	}

	@Override
	public void playBackgroundMusic() {

		playingBackgroundMusic = true;

	}

	@Override
	public void stopBackgroundMusic() {

		playingBackgroundMusic = false;
		currentBackgroundSound.pause();

	}

	public synchronized static IAudioManager init(PApplet p) {
		if (instance != null) {
			throw new RuntimeException("Already Initialized!");
		}
		instance = new AudioManagerImpl(p);
		return instance;
	}

	public static IAudioManager getInstance() {
		if (instance == null) {
			throw new RuntimeException("Not Initialized! Call init first!");
		}
		return instance;
	}

	@Override
	public void update() {
		if (!soundCountdown.isPlaying()) {
			if (playingBackgroundMusic) {
				currentBackgroundSound.play();

				// If nearly finished, isPlaying not working due to
				// multithreading isses and currentPostion() never reaches
				// lenght()
				if (currentBackgroundSound.length() - 1000 < currentBackgroundSound
						.position()) {
					currentBackgroundSound.pause();
					currentBackgroundSound.rewind();

					Random random = new Random();
					int nextSongIndex = random.nextInt(backgroundSounds.size());

					currentBackgroundSound = backgroundSounds
							.get(nextSongIndex);
					currentBackgroundSound.rewind();
					currentBackgroundSound.play();

				}
			}
		} else {
			currentBackgroundSound.pause();
		}
	}

	@Override
	public AudioPlayer createPlayer(String path) {
		return minim.loadFile(path);
	}
}
